﻿using System;
using System.Collections.Generic;

using System.Text;
using System.Web.UI;
using System.ComponentModel;
using TA.Win.Utils.Design;
using System.Drawing.Design;

namespace TA.Turbo.Controls
{
	/// <summary>
	/// The base class for entity controls.
	/// </summary>
	/// <typeparam name="T">Type of the entity.</typeparam>
	/// <typeparam name="C">Type of the underlying control.</typeparam>
	[ParseChildren(true)]
	[PersistChildren(false)]
	public abstract class BaseEntityControl<T, C> : BaseComplexValueControl<T>, IValueControlContainer
		where C : BaseValueDisplayControl, new()
	{
		#region PUBLIC
		#region INIT
		/// <summary>
		/// Ctor.
		/// </summary>
		public BaseEntityControl()
		{
			Tag = HtmlTextWriterTag.Span;

			//Define<string>("ChildId");
		}
		#endregion
		#region PROPS
		#region DEF
		/// <summary>
		/// Props.
		/// </summary>
		protected static new Properties _clientProperties = Define(BaseComplexValueControl<T>._clientProperties,
			new BasePropertyDefinition[] {
				new ControlIdPropertyDefinition("ChildId", "CI", null),
			});
		/// <summary>
		/// Props.
		/// </summary>
		public override Properties ClientProperties
		{
			get
			{
				return _clientProperties;
			}
		}
		#endregion
		/// <summary>
		/// Gets the child control.
		/// </summary>
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
		[Editor(typeof(PropertyEditor), typeof(UITypeEditor))]
		[NotifyParentProperty(true)]
		public virtual C Child { get { return _child; } }
		/// <summary>
		/// When implemented, gets/sets the text value (for a properly data bond entity list, the name of the item, if any)
		/// </summary>
		[Category("Appearance")]
		public abstract string Text { get; set; }
		/// <summary>
		/// The default text value. The Text property will be set to this value upon initial data bind.
		/// </summary>
		public virtual string DefaultText { get; set; }
		/// <summary>
		/// Gets the Child.
		/// </summary>
		[Browsable(false)]
		public TControl Validatable
		{
			get { return this.Child; }
		}
		/// <summary>
		/// Gets the client-side class name.
		/// </summary>
		public override string ClientClassName
		{
			get
			{
				return "$BaseEntityControl";
			}
		}
		public abstract override T Value
		{
			get;
			set;
		}
		#region IValueControlContainer
		/// <summary>
		/// Gets collection of control references which point to the sub-controls that need to be posted in order for this control to be loaded.
		/// </summary>
		[Browsable(false)]
		public List<ControlReference> ValueChildren
		{
			get
			{
				if (_valueChildren == null)
					_valueChildren = CreateValueChildren();
				return _valueChildren;
			}
		}
		/// <summary>
		/// Gets collection of control references which point to the sub-controls that will transfer the properties which this control is not able to transfer itself.
		/// </summary>
		[Browsable(false)]
		public List<ControlReference> PropertiesChildren
		{
			get
			{
				if (this._propertiesChildren == null)
					this._propertiesChildren = this.CreatePropertiesChildren();
				return this._propertiesChildren;
			}
		}
		/// <summary>
		/// Gets the Child.
		/// </summary>
		[Browsable(false)]
		public TControl Focusable
		{
			get { return this.Child; }
		}
		/// <summary>
		/// Gets collection with the only entry being the Child.
		/// </summary>
		[Browsable(false)]
		public virtual List<TControl> RequiredValidationFields
		{
			get
			{
				List<TControl> res = new List<TControl>();
				res.Add(this.Child);
				return res;
			}
		}
		#endregion
		#endregion
		#region METHODS
		/// <summary>
		/// Performs the databinding necessary to init the control, if any.
		/// </summary>
		public virtual void Bind()
		{
		}
		#endregion
		#region EVENTS
		#endregion
		#endregion
		#region INTERNAL
		#region VARS
		C _child;
		List<ControlReference> _valueChildren, _propertiesChildren;
		#endregion
		#region PROPS
		/// <summary>
		/// Gets or sets a flag which indicates whether child's value changed event should be raised even if no handlers
		/// are assigned to this entity control's value changed event.
		/// </summary>
		protected bool CaptureValueChanged { get; set; }
		protected internal sealed override string SerializedValue
		{
			get
			{
				throw new NotSupportedException();
			}
			set
			{
				throw new NotSupportedException();
			}
		}
		#endregion
		#region METHODS
		#region INIT
		/// <summary>
		/// Called when property-transferring controls need to be created.
		/// </summary>
		/// <returns></returns>
		private List<ControlReference> CreatePropertiesChildren()
		{
			List<ControlReference> res = new List<ControlReference>();
			res.Add(new ControlReference(this.Child));
			return res;
		}
		/// <summary>
		/// Called when value-transferring controls need to be created.
		/// </summary>
		/// <returns></returns>
		protected virtual List<ControlReference> CreateValueChildren()
		{
			List<ControlReference> res = new List<ControlReference>();
			res.Add(new ControlReference(this.Child));
			return res;
		}
		/// <summary>
		/// Registers BaseEntityControl.js. 
		/// </summary>
		protected internal override void RegisterIncludes(IncludeCollection includes)
		{
			base.RegisterIncludes(includes);

			includes.Add(Script.String_IsNullOrEmpty);
			includes.Add(new ScriptResourceInclude("TA.Turbo.Res.JS.Entity.BaseEntityControl.js", typeof(BaseEntityControl<T, C>)));
		}
		/// <summary>
		/// Initialization.
		/// </summary>
		/// <param name="e"></param>
		protected override void OnInit(EventArgs e)
		{
			base.OnInit(e);

			this.CreateChild();
			if (!this.get_IsDesignMode())
			{
				if (this.Child != null)
				{
					if (string.IsNullOrEmpty(this.Child.ID))
						this.Child.ID = this.ID + "_Child";
					if (string.IsNullOrEmpty(this.Child.Attributes["style"]))
						this.Child.Attributes["style"] = this.Attributes["style"];
					if (this.Child.Parent == null)
						this.Controls.Add(this.Child);


					ViewState["ChildId"] = this.Child.ID;
				}
				CreateAdditional();

				ChildControlsCreated = true;

				Bind();
			}
		}
		/// <summary>
		/// Creates the underlying child control.
		/// </summary>
		protected virtual void CreateChild()
		{
			_child = new C();
		}
		/// <summary>
		/// Creates additional controls which are needed for the operation of this entity control (such as validators).
		/// </summary>
		protected virtual void CreateAdditional()
		{
		}
		#endregion
		#region HANDLERS
		/// <summary>
		/// Handler for the child control's value changed event.
		/// </summary>
		/// <param name="s"></param>
		/// <param name="e"></param>
		protected void Child_ValueChanged(object s, EventArgs e)
		{
			OnValueChanged(e);
		}

		#endregion
		#region DATA
		#endregion
		#region EVENTS
		#endregion
		#region RENDER
		/// <summary>
		/// Appends attribute(s) for value.
		/// </summary>
		/// <param name="writer"></param>
		protected override void AddValueAttributes(HtmlTextWriter writer)
		{
		}
		public override void RenderLoadScriptInternal(HtmlTextWriter writer, string varName)
		{
		}
		/// <summary>
		/// Outputs the content of a server control's children to a provided System.Web.UI.HtmlTextWriter object, which writes the content to be rendered on the client.
		/// </summary>
		/// <param name="writer"></param>
		protected override void RenderChildren(HtmlTextWriter writer)
		{
			if (this.get_IsDesignMode())
			{
				try
				{
					this.Controls.Add(this.Child);
					base.RenderChildren(writer);
					this.Controls.Remove(this.Child);
				}
				catch
				{
				}
			}
			else
			{
				base.RenderChildren(writer);
			}
		}
		#endregion
		#endregion
		#endregion

	}
}
